﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Deployment.Application;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Globalization;
using Xmef.Interfaces;

namespace Xmef.Library
{
    [Serializable]
    public sealed class Program<T> : IProgram<T>, IDisposable where T : Form, new()
    {
        private T _window;

        private Program() { }

        private static IProgram<T> _program;

        public static void Run()
        {
            try
            {
                using (var traceListener = new TextWriterTraceListener(File.Open("application.session.txt", FileMode.Create, FileAccess.Write, FileShare.None)))
                using (var errorStream = new StreamWriter(File.Open("application.errors.txt", FileMode.Create, FileAccess.Write, FileShare.None)))
                using (var outputStream = new StreamWriter(File.Open("application.output.txt", FileMode.Create, FileAccess.Write, FileShare.None)))
                {
                    Trace.Listeners.Add(traceListener);
                    Console.SetError(errorStream);
                    Console.SetOut(outputStream);
                    if (OSFeature.Feature.IsPresent(OSFeature.Themes))
                    {
                        _program = new Program<T>();
                        _program.Update();
                        Application.Run(_program.Window);
                    }
                }
            }
            catch (Exception ex)
            {
                using (var errorStream = new StreamWriter(File.Open("application.exception.txt", FileMode.Create, FileAccess.Write, FileShare.None)))
                {
                    Console.SetError(errorStream);
                    LogHelper.WriteErrorSync(ex);
                }
                MessageBox.Show(string.Format(CultureInfo.InvariantCulture, "This application is designed to run only under Microsoft Windows XP or later operation system environment with latest service packs installed.{0}Check application log files for more details.", Environment.NewLine), "{sudoku}", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        public T Window
        {
            get
            {
                if (_window == null)
                {
                    _window = new T();
                }
                return _window;
            }
        }

        public void Update()
        {
            UpdateCheckInfo info = null;

            if (ApplicationDeployment.IsNetworkDeployed)
            {
                ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;

                try
                {
                    info = ad.CheckForDetailedUpdate();

                }
                catch (DeploymentDownloadException dde)
                {
                    MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
                    return;
                }
                catch (InvalidDeploymentException ide)
                {
                    MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
                    return;
                }
                catch (InvalidOperationException ioe)
                {
                    MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
                    return;
                }

                if (info.UpdateAvailable)
                {
                    Boolean doUpdate = true;

                    if (!info.IsUpdateRequired)
                    {
                        DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
                        if (!(DialogResult.OK == dr))
                        {
                            doUpdate = false;
                        }
                    }
                    else
                    {
                        // Display a message that the app MUST reboot. Display the minimum required version.
                        MessageBox.Show("This application has detected a mandatory update from your current " +
                            "version to version " + info.MinimumRequiredVersion.ToString() +
                            ". The application will now install the update and restart.",
                            "Update Available", MessageBoxButtons.OK,
                            MessageBoxIcon.Information);
                    }

                    if (doUpdate)
                    {
                        try
                        {
                            ad.Update();
                            MessageBox.Show("The application has been upgraded, and will now restart.");
                            Application.Restart();
                        }
                        catch (DeploymentDownloadException dde)
                        {
                            MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
                            return;
                        }
                    }
                }
            }
        }
        public void Load(string groupName)
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                ApplicationDeployment deploy = ApplicationDeployment.CurrentDeployment;

                if (deploy.IsFirstRun)
                {
                    try
                    {
                        deploy.DownloadFileGroup(groupName);
                    }
                    catch (DeploymentException ex)
                    {
                        LogHelper.WriteErrorSync(ex);
                    }
                }
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_window != null)
            {
                _window.Dispose();
                _window = null;
            }
        }

        #endregion
    }
}
